﻿using System.Collections;
using Consul;
using Infrastructure.Helper;
using Infrastructure.Model.ApiResult;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using zipkin4net;
using zipkin4net.Tracers.Zipkin;
using zipkin4net.Transport.Http;

namespace Infrastructure.Centers
{
    // 静态工具类：用于服务注册（Consul）和分布式跟踪（Zipkin）的配置
    public static class RegistryConsul
    {
        /// <summary>
        /// 将当前微服务注册到 Consul 服务发现中心
        /// </summary>
        /// <param name="app">应用程序构建器</param>
        /// <param name="lifetime">应用生命周期管理，用于注册停止事件</param>
        /// <param name="setupAction">服务中心配置选项</param>
        /// <returns>IApplicationBuilder 用于链式调用</returns>
        public static IApplicationBuilder RegisterService(this IApplicationBuilder app, IHostApplicationLifetime lifetime, IOptions<ServiceCenterOption> setupAction)
        {
            // 如果配置中没有提供 Consul URL，则通过服务中心获取
            if (string.IsNullOrWhiteSpace(setupAction.Value.ConsulUrl))
            {
                // 调用 Restful API 获取 Consul URL
                ApiResult apiResult = new RestfulHelper().Post(setupAction.Value.ServiceCenterUrl + "/" + setupAction.Value.GetConsulUrl, new Hashtable {
                {
                    "ServiceName",
                    setupAction.Value.ServiceName
                }
            });

                // 如果返回失败，抛出异常
                if (!apiResult.IsSuccess)
                {
                    throw new Exception("Register Consul Error : " + apiResult.Msg);
                }

                // 将返回的数据作为 Consul URL，并移除多余的引号
                setupAction.Value.ConsulUrl = apiResult.Data.ToString().Replace("\"", "");
            }

            // 创建 Consul 客户端，并设置 Consul 服务的 URL 地址
            ConsulClient client = new ConsulClient(delegate (ConsulClientConfiguration options)
            {
                options.Address = new Uri(setupAction.Value.ConsulUrl); // Consul 服务地址
            });

            // 配置服务注册信息
            AgentServiceRegistration registration = new AgentServiceRegistration
            {
                ID = Guid.NewGuid().ToString(), // 生成唯一的服务 ID
                Name = setupAction.Value.ServiceName, // 服务名称
                Address = setupAction.Value.LocalIP, // 服务所在的本地 IP 地址
                Port = setupAction.Value.LocalPort, // 服务所在的端口号
                Check = new AgentServiceCheck
                {
                    // 配置健康检查
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5.0), // 如果服务出现问题，5秒后将其注销
                    Interval = TimeSpan.FromSeconds(10.0), // 健康检查间隔时间
                    HTTP = $"http://{setupAction.Value.LocalIP}:{setupAction.Value.LocalPort}/{setupAction.Value.HealthCheckUrl}", // 健康检查的 URL
                    Timeout = TimeSpan.FromSeconds(5.0) // 健康检查超时设置
                }
            };

            // 注册服务到 Consul
            client.Agent.ServiceRegister(registration).Wait();

            // 当应用停止时，从 Consul 注销服务
            lifetime.ApplicationStopping.Register(delegate
            {
                client.Agent.ServiceDeregister(registration.ID).Wait();
            });

            return app; // 返回应用程序构建器，以便链式调用
        }
        /// <summary>
        /// 配置分布式跟踪系统（Zipkin）
        /// </summary>
        /// <param name="app">应用程序构建器</param>
        /// <param name="lifetime">应用生命周期管理</param>
        /// <param name="setupAction">服务中心配置选项</param>
        /// <returns>IApplicationBuilder 用于链式调用</returns>
        public static IApplicationBuilder RegisterTracer(this IApplicationBuilder app, IHostApplicationLifetime lifetime, IOptions<ServiceCenterOption> setupAction)
        {
            // 如果跟踪系统尚未启动，则进行初始化
            if (!TraceManager.Started)
            {
                // 使用中间件启用跟踪
                app.UseMiddleware<TracingMiddleware>(Array.Empty<object>());

                // 如果没有提供 Zipkin URL，则从服务中心获取
                if (string.IsNullOrWhiteSpace(setupAction.Value.ZipkinUrl))
                {
                    // 调用 Restful API 获取 Zipkin URL
                    ApiResult apiResult = new RestfulHelper(setupAction.Value.AccessToken).Post(setupAction.Value.ServiceCenterUrl + "/" + setupAction.Value.GetZipkinUrl, new ZipkinObj
                    {
                        ServiceName = setupAction.Value.ServiceName // 传递服务名称
                    });

                    // 如果返回失败，抛出异常
                    if (!apiResult.IsSuccess)
                    {
                        throw new Exception("Register Zipkin Error : " + apiResult.Msg);
                    }

                    // 将返回的数据作为 Zipkin URL，并移除多余的引号
                    setupAction.Value.ZipkinUrl = apiResult.Data.ToString().Replace("\"", "");
                }

                // 设置采样率为 100%
                TraceManager.SamplingRate = 1f;

                // 创建控制台日志记录器
                ConsoleLogger logger = new ConsoleLogger();

                // 创建 Zipkin 发送器，负责将跟踪信息发送到 Zipkin
                HttpZipkinSender sender = new HttpZipkinSender(setupAction.Value.ZipkinUrl, "application/json");

                // 创建 Zipkin 跟踪器
                ZipkinTracer tracer = new ZipkinTracer(sender, new JSONSpanSerializer());

                // 注册 Zipkin 跟踪器
                TraceManager.RegisterTracer(tracer);

                // 启动 TraceManager（负责全局的跟踪管理）
                TraceManager.Start(logger);
            }

            return app; // 返回应用程序构建器，以便链式调用
        }
    }

}
